Skip to content

Fix AST optionality - #65063

Merged
Andrew Branch (andrewbranch) merged 3 commits into
microsoft:mainfrom
andrewbranch:ast-optionality-fix
Nov 3, 2026
Merged

Andrew Branch (andrewbranch) merged 3 commits into
microsoft:mainfrom
andrewbranch:ast-optionality-fix

Conversation

@andrewbranch

@andrewbranch Andrew Branch (andrewbranch) commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Fixes #64864

Changed

  • ExportAssignment.type is now optional. Undefined for export default 0;.

  • PropertySignatureDeclaration.type is now optional. Undefined for p in interface I { p; }.

  • PropertySignatureDeclaration.initializer is now optional. Undefined for p in interface I { p: string; }.

  • IndexSignatureDeclaration.type is now optional. Undefined for interface I { [key: string] /*: missing type here */; }. Extracted to Make index signature declarations without a type annotation an implicit any, not a grammar error #65283

  • ArrowFunction.equalsGreaterThanToken is now non-nil even for synthesized arrow functions, matching Strada's behavior.

  • TaggedTemplateExpression.questionDotToken is now optional. Undefined for tag`text`.

  • PropertyAssignment.type is now optional. Undefined for p in const obj = { p: 1 };.

  • ShorthandPropertyAssignment.type is now optional. Undefined for p in const obj = { p };.

  • JSDocTemplateTag.constraint is now optional. Undefined for /** @template T */ function f() {}.

  • JSDocSeeTag.nameExpression is now optional. Undefined for /** @see */ function f() {} (missing reference).

  • FunctionTypeNode.type is now required. In type F = () => number, it is the number type node; parser recovery also supplies a node when the return type is missing.

  • ConstructorTypeNode.type is now required. In type C = new () => object, it is the object type node; parser recovery likewise supplies a node when missing.

  • Separated CaseClause and DefaultClause in the schema and Go AST. CaseClause.expression remains required; DefaultClause has no expression property. CaseOrDefaultClause is a union, with shared statements/flow data in a base.

  • Factory-created boolean properties now default to false rather than undefined: Block.multiLine, ArrayLiteralExpression.multiLine, ObjectLiteralExpression.multiLine, ImportAttributes.multiLine, ExportDeclaration.isTypeOnly, SyntheticExpression.isSpread, JsxText.containsOnlyTriviaWhiteSpaces, and JSDocTypeLiteral.isArrayType.

  • Factory-created node arrays now initialize transformFlags to 0.

  • Factory-created nodes now compute modifierFlags from their modifiers, matching parsed nodes: None without modifiers, otherwise the combined syntactic modifier bitmask.

Not changed

node.parent is still typed as non-optional, which is a convenient lie inherited from Strada, and changing it would be pretty disruptive.

Copilot AI balanced review requested due to automatic review settings October 30, 2026 19:23
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Oct 30, 2026
@typescript-automation typescript-automation Bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Oct 30, 2026
@github-project-automation github-project-automation Bot moved this from Not started to Needs merge in PR Backlog Oct 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the AST contract alignment and case/default clause separation.

No open issues 🎉

3 files not reviewed
  • tsc/internal/api/encoder/decoder_generated.go: Generated file
  • tsc/internal/api/encoder/encoder_generated.go: Generated file
  • tsc/internal/ast/ast_generated.go: Generated file
What changed in this PR

Addresses #64864 by aligning JavaScript API AST types with runtime values and updating the native compiler to use distinct case and default clause nodes.

Changes:

  • Corrects AST property optionality and removes expression from DefaultClause.
  • Ensures synthesized arrows have => tokens and initializes factory boolean values, modifier flags, and node-array transform flags.
  • Updates generators, serialization, compiler consumers, and regression tests to preserve these contracts.
File Description
tsc/​internal/​transformers/​moduletransforms/​commonjsmodule.go Updates case and default clauses separately during transformation.
tsc/​internal/​printer/​printer.go Prints distinct clause types through shared statement accessors.
tsc/​internal/​printer/​printer_test.go Exercises arrow printing with an omitted token.
tsc/​internal/​parser/​parser.go Constructs separate case and default nodes.
tsc/​internal/​ls/​utilities.go Updates clause tracking to use the union alias.
tsc/​internal/​ls/​folding.go Uses shared clause statement accessors for folding.
tsc/​internal/​ls/​completions.go Updates clause types and completion factories.
tsc/​internal/​checker/​checker.go Reads fallthrough data from the shared clause base.
tsc/​internal/​binder/​binder.go Adapts clause binding and fallthrough storage.
tsc/​internal/​ast/​nodeaccessors_test.go Tests arrow tokens, clause accessors, traversal, and cloning.
tsc/​internal/​ast/​ast.go Updates expression and statement accessors for split clauses.
tsc/​internal/​ast/​ast_generated.go Regenerates clause structures, factories, dispatch, and optionality comments.
tsc/​internal/​api/​encoder/​encoder_generated.go Encodes distinct child layouts for each clause type.
tsc/​internal/​api/​encoder/​decoder_generated.go Decodes clauses using their separate factories.
tools/​scripts/​tsc/​generate-ts-ast.ts Generates factory defaults and computed modifier flags.
tools/​scripts/​tsc/​generate-go-ast.ts Generates arrow-token defaults and shared clause accessors.
tools/​scripts/​tsc/​ast.json Defines corrected optionality and separate clause schemas.
packages/​typescript/​test/​sync/​ast.test.ts Adds runtime and type-level AST contract tests.
packages/​typescript/​src/​ast/​visitor.generated.ts Removes expression visitation from default clauses.
packages/​typescript/​src/​ast/​is.generated.ts Regenerates clause guards and adds a union guard.
packages/​typescript/​src/​ast/​factory.generated.ts Applies corrected factory signatures, defaults, and clause handling.
packages/​typescript/​src/​ast/​ast.ts Removes default clauses from HasExpression.
packages/​typescript/​src/​ast/​ast.generated.ts Exposes corrected property types and clause interfaces.
packages/​typescript/​src/​api/​node/​protocol.generated.ts Aligns default-clause protocol metadata with its statement-only layout.

Review effort: Balanced

@RyanCavanaugh

Copy link
Copy Markdown
Member

IndexSignatureDeclaration.type is now optional. Undefined for interface I { [key: string]

This is the only item in the entire list that's a syntax error, so seems out of place?

@andrewbranch
Andrew Branch (andrewbranch) added this pull request to the merge queue Oct 30, 2026
@andrewbranch
Andrew Branch (andrewbranch) removed this pull request from the merge queue due to a manual request Oct 30, 2026
@andrewbranch

Copy link
Copy Markdown
Member Author

Good catch; I misremembered that as legal along with interface I { p }. Strada typed it as non-optional but the parser doesn't produce a missing node there during recovery—actually, the syntax error you see is a grammar error, not a parse error.

This does seem to be the only case where an optional node child property is always defined in error-free code, so there's no other precedent to go on. Other grammar errors like this are context-dependent, e.g. VariableDeclaration.initializer is allowed to be missing in let x; but an error in const x;. I think the right option is either to keep it optional (as is in this PR), or to make it a proper parse error and synthesizing a missing identifier.

@andrewbranch

Copy link
Copy Markdown
Member Author

Tried a few different things, and we decided it would be worth looking into just making interface I { [p: string] } a syntactically legal implicit any, as I had originally remembered it. I'm going to extract that into a separate PR and remove any index signature declaration changes from this one.

@jakebailey Jake Bailey (jakebailey) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I realized a bug I was working on depended on this too

@andrewbranch
Andrew Branch (andrewbranch) added this pull request to the merge queue Nov 3, 2026
Merged via the queue into microsoft:main with commit 1b86397 Nov 3, 2026
61 of 63 checks passed
@andrewbranch
Andrew Branch (andrewbranch) deleted the ast-optionality-fix branch November 3, 2026 18:15
@github-project-automation github-project-automation Bot moved this from Needs merge to Done in PR Backlog Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Some JS API types don't match their runtime values

4 participants